home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / net_wins.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  19.4 KB  |  855 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // net_wins.c
  21.  
  22. #include "winsock.h"
  23. #include "wsipx.h"
  24. #include "../qcommon/qcommon.h"
  25.  
  26. #define    MAX_LOOPBACK    4
  27.  
  28. typedef struct
  29. {
  30.     byte    data[MAX_MSGLEN];
  31.     int        datalen;
  32. } loopmsg_t;
  33.  
  34. typedef struct
  35. {
  36.     loopmsg_t    msgs[MAX_LOOPBACK];
  37.     int            get, send;
  38. } loopback_t;
  39.  
  40.  
  41. cvar_t        *net_shownet;
  42. static cvar_t    *noudp;
  43. static cvar_t    *noipx;
  44.  
  45. loopback_t    loopbacks[2];
  46. int            ip_sockets[2];
  47. int            ipx_sockets[2];
  48.  
  49. char *NET_ErrorString (void);
  50.  
  51. //=============================================================================
  52.  
  53. void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
  54. {
  55.     memset (s, 0, sizeof(*s));
  56.  
  57.     if (a->type == NA_BROADCAST)
  58.     {
  59.         ((struct sockaddr_in *)s)->sin_family = AF_INET;
  60.         ((struct sockaddr_in *)s)->sin_port = a->port;
  61.         ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
  62.     }
  63.     else if (a->type == NA_IP)
  64.     {
  65.         ((struct sockaddr_in *)s)->sin_family = AF_INET;
  66.         ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
  67.         ((struct sockaddr_in *)s)->sin_port = a->port;
  68.     }
  69.     else if (a->type == NA_IPX)
  70.     {
  71.         ((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
  72.         memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
  73.         memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
  74.         ((struct sockaddr_ipx *)s)->sa_socket = a->port;
  75.     }
  76.     else if (a->type == NA_BROADCAST_IPX)
  77.     {
  78.         ((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
  79.         memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
  80.         memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
  81.         ((struct sockaddr_ipx *)s)->sa_socket = a->port;
  82.     }
  83. }
  84.  
  85. void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
  86. {
  87.     if (s->sa_family == AF_INET)
  88.     {
  89.         a->type = NA_IP;
  90.         *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
  91.         a->port = ((struct sockaddr_in *)s)->sin_port;
  92.     }
  93.     else if (s->sa_family == AF_IPX)
  94.     {
  95.         a->type = NA_IPX;
  96.         memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
  97.         memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
  98.         a->port = ((struct sockaddr_ipx *)s)->sa_socket;
  99.     }
  100. }
  101.  
  102.  
  103. qboolean    NET_CompareAdr (netadr_t a, netadr_t b)
  104. {
  105.     if (a.type != b.type)
  106.         return false;
  107.  
  108.     if (a.type == NA_LOOPBACK)
  109.         return TRUE;
  110.  
  111.     if (a.type == NA_IP)
  112.     {
  113.         if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
  114.             return true;
  115.     }
  116.  
  117.     if (a.type == NA_IPX)
  118.     {
  119.         if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
  120.             return true;
  121.     }
  122.  
  123.     return false;
  124. }
  125.  
  126. /*
  127. ===================
  128. NET_CompareBaseAdr
  129.  
  130. Compares without the port
  131. ===================
  132. */
  133. qboolean    NET_CompareBaseAdr (netadr_t a, netadr_t b)
  134. {
  135.     if (a.type != b.type)
  136.         return false;
  137.  
  138.     if (a.type == NA_LOOPBACK)
  139.         return TRUE;
  140.  
  141.     if (a.type == NA_IP)
  142.     {
  143.         if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
  144.             return true;
  145.     }
  146.  
  147.     if (a.type == NA_IPX)
  148.     {
  149.         if ((memcmp(a.ipx, b.ipx, 10) == 0))
  150.             return true;
  151.     }
  152.  
  153.     return false;
  154. }
  155.  
  156. char    *NET_AdrToString (netadr_t a)
  157. {
  158.     static    char    s[64];
  159.  
  160.     if (a.type == NA_LOOPBACK)
  161.         Com_sprintf (s, sizeof(s), "loopback");
  162.     else if (a.type == NA_IP)
  163.         Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
  164.     else
  165.         Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
  166.  
  167.     return s;
  168. }
  169.  
  170.  
  171. /*
  172. =============
  173. NET_StringToAdr
  174.  
  175. localhost
  176. idnewt
  177. idnewt:28000
  178. 192.246.40.70
  179. 192.246.40.70:28000
  180. =============
  181. */
  182. #define DO(src,dest)    \
  183.     copy[0] = s[src];    \
  184.     copy[1] = s[src + 1];    \
  185.     sscanf (copy, "%x", &val);    \
  186.     ((struct sockaddr_ipx *)sadr)->dest = val
  187.  
  188. qboolean    NET_StringToSockaddr (char *s, struct sockaddr *sadr)
  189. {
  190.     struct hostent    *h;
  191.     char    *colon;
  192.     int        val;
  193.     char    copy[128];
  194.     
  195.     memset (sadr, 0, sizeof(*sadr));
  196.  
  197.     if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':'))    // check for an IPX address
  198.     {
  199.         ((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
  200.         copy[2] = 0;
  201.         DO(0, sa_netnum[0]);
  202.         DO(2, sa_netnum[1]);
  203.         DO(4, sa_netnum[2]);
  204.         DO(6, sa_netnum[3]);
  205.         DO(9, sa_nodenum[0]);
  206.         DO(11, sa_nodenum[1]);
  207.         DO(13, sa_nodenum[2]);
  208.         DO(15, sa_nodenum[3]);
  209.         DO(17, sa_nodenum[4]);
  210.         DO(19, sa_nodenum[5]);
  211.         sscanf (&s[22], "%u", &val);
  212.         ((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
  213.     }
  214.     else
  215.     {
  216.         ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
  217.         
  218.         ((struct sockaddr_in *)sadr)->sin_port = 0;
  219.  
  220.         strcpy (copy, s);
  221.         // strip off a trailing :port if present
  222.         for (colon = copy ; *colon ; colon++)
  223.             if (*colon == ':')
  224.             {
  225.                 *colon = 0;
  226.                 ((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));    
  227.             }
  228.         
  229.         if (copy[0] >= '0' && copy[0] <= '9')
  230.         {
  231.             *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
  232.         }
  233.         else
  234.         {
  235.             if (! (h = gethostbyname(copy)) )
  236.                 return 0;
  237.             *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
  238.         }
  239.     }
  240.     
  241.     return true;
  242. }
  243.  
  244. #undef DO
  245.  
  246. /*
  247. =============
  248. NET_StringToAdr
  249.  
  250. localhost
  251. idnewt
  252. idnewt:28000
  253. 192.246.40.70
  254. 192.246.40.70:28000
  255. =============
  256. */
  257. qboolean    NET_StringToAdr (char *s, netadr_t *a)
  258. {
  259.     struct sockaddr sadr;
  260.     
  261.     if (!strcmp (s, "localhost"))
  262.     {
  263.         memset (a, 0, sizeof(*a));
  264.         a->type = NA_LOOPBACK;
  265.         return true;
  266.     }
  267.  
  268.     if (!NET_StringToSockaddr (s, &sadr))
  269.         return false;
  270.     
  271.     SockadrToNetadr (&sadr, a);
  272.  
  273.     return true;
  274. }
  275.  
  276.  
  277. qboolean    NET_IsLocalAddress (netadr_t adr)
  278. {
  279.     return adr.type == NA_LOOPBACK;
  280. }
  281.  
  282. /*
  283. =============================================================================
  284.  
  285. LOOPBACK BUFFERS FOR LOCAL PLAYER
  286.  
  287. =============================================================================
  288. */
  289.  
  290. qboolean    NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
  291. {
  292.     int        i;
  293.     loopback_t    *loop;
  294.  
  295.     loop = &loopbacks[sock];
  296.  
  297.     if (loop->send - loop->get > MAX_LOOPBACK)
  298.         loop->get = loop->send - MAX_LOOPBACK;
  299.  
  300.     if (loop->get >= loop->send)
  301.         return false;
  302.  
  303.     i = loop->get & (MAX_LOOPBACK-1);
  304.     loop->get++;
  305.  
  306.     memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
  307.     net_message->cursize = loop->msgs[i].datalen;
  308.     memset (net_from, 0, sizeof(*net_from));
  309.     net_from->type = NA_LOOPBACK;
  310.     return true;
  311.  
  312. }
  313.  
  314.  
  315. void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
  316. {
  317.     int        i;
  318.     loopback_t    *loop;
  319.  
  320.     loop = &loopbacks[sock^1];
  321.  
  322.     i = loop->send & (MAX_LOOPBACK-1);
  323.     loop->send++;
  324.  
  325.     memcpy (loop->msgs[i].data, data, length);
  326.     loop->msgs[i].datalen = length;
  327. }
  328.  
  329. //=============================================================================
  330.  
  331. qboolean    NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
  332. {
  333.     int     ret;
  334.     struct sockaddr from;
  335.     int        fromlen;
  336.     int        net_socket;
  337.     int        protocol;
  338.     int        err;
  339.  
  340.     if (NET_GetLoopPacket (sock, net_from, net_message))
  341.         return true;
  342.  
  343.     for (protocol = 0 ; protocol < 2 ; protocol++)
  344.     {
  345.         if (protocol == 0)
  346.             net_socket = ip_sockets[sock];
  347.         else
  348.             net_socket = ipx_sockets[sock];
  349.  
  350.         if (!net_socket)
  351.             continue;
  352.  
  353.         fromlen = sizeof(from);
  354.         ret = recvfrom (net_socket, net_message->data, net_message->maxsize
  355.             , 0, (struct sockaddr *)&from, &fromlen);
  356.  
  357.         SockadrToNetadr (&from, net_from);
  358.  
  359.         if (ret == -1)
  360.         {
  361.             err = WSAGetLastError();
  362.  
  363.             if (err == WSAEWOULDBLOCK)
  364.                 continue;
  365.             if (err == WSAEMSGSIZE) {
  366.                 Com_Printf ("Warning:  Oversize packet from %s\n",
  367.                         NET_AdrToString(*net_from));
  368.                 continue;
  369.             }
  370.  
  371.             if (dedicated->value)    // let dedicated servers continue after errors
  372.                 Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
  373.                         NET_AdrToString(*net_from));
  374.             else
  375.                 Com_Error (ERR_DROP, "NET_GetPacket: %s from %s", 
  376.                         NET_ErrorString(), NET_AdrToString(*net_from));
  377.             continue;
  378.         }
  379.  
  380.         if (ret == net_message->maxsize)
  381.         {
  382.             Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
  383.             continue;
  384.         }
  385.  
  386.         net_message->cursize = ret;
  387.         return true;
  388.     }
  389.  
  390.     return false;
  391. }
  392.  
  393. //=============================================================================
  394.  
  395. void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
  396. {
  397.     int        ret;
  398.     struct sockaddr    addr;
  399.     int        net_socket;
  400.  
  401.     if ( to.type == NA_LOOPBACK )
  402.     {
  403.         NET_SendLoopPacket (sock, length, data, to);
  404.         return;
  405.     }
  406.  
  407.     if (to.type == NA_BROADCAST)
  408.     {
  409.         net_socket = ip_sockets[sock];
  410.         if (!net_socket)
  411.             return;
  412.     }
  413.     else if (to.type == NA_IP)
  414.     {
  415.         net_socket = ip_sockets[sock];
  416.         if (!net_socket)
  417.             return;
  418.     }
  419.     else if (to.type == NA_IPX)
  420.     {
  421.         net_socket = ipx_sockets[sock];
  422.         if (!net_socket)
  423.             return;
  424.     }
  425.     else if (to.type == NA_BROADCAST_IPX)
  426.     {
  427.         net_socket = ipx_sockets[sock];
  428.         if (!net_socket)
  429.             return;
  430.     }
  431.     else
  432.         Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
  433.  
  434.     NetadrToSockadr (&to, &addr);
  435.  
  436.     ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
  437.     if (ret == -1)
  438.     {
  439.         int err = WSAGetLastError();
  440.  
  441.         // wouldblock is silent
  442.         if (err == WSAEWOULDBLOCK)
  443.             return;
  444.  
  445.         // some PPP links dont allow broadcasts
  446.         if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
  447.             return;
  448.  
  449.         if (dedicated->value)    // let dedicated servers continue after errors
  450.         {
  451.             Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
  452.                 NET_AdrToString (to));
  453.         }
  454.         else
  455.         {
  456.             if (err == WSAEADDRNOTAVAIL)
  457.             {
  458.                 Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", 
  459.                         NET_ErrorString(), NET_AdrToString (to));
  460.             }
  461.             else
  462.             {
  463.                 Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s to %s\n", 
  464.                         NET_ErrorString(), NET_AdrToString (to));
  465.             }
  466.         }
  467.     }
  468. }
  469.  
  470.  
  471. //=============================================================================
  472.  
  473.  
  474. /*
  475. ====================
  476. NET_Socket
  477. ====================
  478. */
  479. int NET_IPSocket (char *net_interface, int port)
  480. {
  481.     int                    newsocket;
  482.     struct sockaddr_in    address;
  483.     qboolean            _true = true;
  484.     int                    i = 1;
  485.     int                    err;
  486.  
  487.     if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  488.     {
  489.         err = WSAGetLastError();
  490.         if (err != WSAEAFNOSUPPORT)
  491.             Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
  492.         return 0;
  493.     }
  494.  
  495.     // make it non-blocking
  496.     if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
  497.     {
  498.         Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
  499.         return 0;
  500.     }
  501.  
  502.     // make it broadcast capable
  503.     if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
  504.     {
  505.         Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
  506.         return 0;
  507.     }
  508.  
  509.     if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
  510.         address.sin_addr.s_addr = INADDR_ANY;
  511.     else
  512.         NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  513.  
  514.     if (port == PORT_ANY)
  515.         address.sin_port = 0;
  516.     else
  517.         address.sin_port = htons((short)port);
  518.  
  519.     address.sin_family = AF_INET;
  520.  
  521.     if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
  522.     {
  523.         Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
  524.         closesocket (newsocket);
  525.         return 0;
  526.     }
  527.  
  528.     return newsocket;
  529. }
  530.  
  531.  
  532. /*
  533. ====================
  534. NET_OpenIP
  535. ====================
  536. */
  537. void NET_OpenIP (void)
  538. {
  539.     cvar_t    *ip;
  540.     int        port;
  541.     int        dedicated;
  542.  
  543.     ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
  544.  
  545.     dedicated = Cvar_VariableValue ("dedicated");
  546.  
  547.     if (!ip_sockets[NS_SERVER])
  548.     {
  549.         port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
  550.         if (!port)
  551.         {
  552.             port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
  553.             if (!port)
  554.             {
  555.                 port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
  556.             }
  557.         }
  558.         ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
  559.         if (!ip_sockets[NS_SERVER] && dedicated)
  560.             Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
  561.     }
  562.  
  563.  
  564.     // dedicated servers don't need client ports
  565.     if (dedicated)
  566.         return;
  567.  
  568.     if (!ip_sockets[NS_CLIENT])
  569.     {
  570.         port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
  571.         if (!port)
  572.         {
  573.             port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
  574.             if (!port)
  575.                 port = PORT_ANY;
  576.         }
  577.         ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
  578.         if (!ip_sockets[NS_CLIENT])
  579.             ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
  580.     }
  581. }
  582.  
  583.  
  584. /*
  585. ====================
  586. IPX_Socket
  587. ====================
  588. */
  589. int NET_IPXSocket (int port)
  590. {
  591.     int                    newsocket;
  592.     struct sockaddr_ipx    address;
  593.     int                    _true = 1;
  594.     int                    err;
  595.  
  596.     if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
  597.     {
  598.         err = WSAGetLastError();
  599.         if (err != WSAEAFNOSUPPORT)
  600.             Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
  601.         return 0;
  602.     }
  603.  
  604.     // make it non-blocking
  605.     if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
  606.     {
  607.         Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
  608.         return 0;
  609.     }
  610.  
  611.     // make it broadcast capable
  612.     if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
  613.     {
  614.         Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
  615.         return 0;
  616.     }
  617.  
  618.     address.sa_family = AF_IPX;
  619.     memset (address.sa_netnum, 0, 4);
  620.     memset (address.sa_nodenum, 0, 6);
  621.     if (port == PORT_ANY)
  622.         address.sa_socket = 0;
  623.     else
  624.         address.sa_socket = htons((short)port);
  625.  
  626.     if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
  627.     {
  628.         Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
  629.         closesocket (newsocket);
  630.         return 0;
  631.     }
  632.  
  633.     return newsocket;
  634. }
  635.  
  636.  
  637. /*
  638. ====================
  639. NET_OpenIPX
  640. ====================
  641. */
  642. void NET_OpenIPX (void)
  643. {
  644.     int        port;
  645.     int        dedicated;
  646.  
  647.     dedicated = Cvar_VariableValue ("dedicated");
  648.  
  649.     if (!ipx_sockets[NS_SERVER])
  650.     {
  651.         port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
  652.         if (!port)
  653.         {
  654.             port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
  655.             if (!port)
  656.             {
  657.                 port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
  658.             }
  659.         }
  660.         ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
  661.     }
  662.  
  663.     // dedicated servers don't need client ports
  664.     if (dedicated)
  665.         return;
  666.  
  667.     if (!ipx_sockets[NS_CLIENT])
  668.     {
  669.         port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
  670.         if (!port)
  671.         {
  672.             port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
  673.             if (!port)
  674.                 port = PORT_ANY;
  675.         }
  676.         ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
  677.         if (!ipx_sockets[NS_CLIENT])
  678.             ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
  679.     }
  680. }
  681.  
  682.  
  683. /*
  684. ====================
  685. NET_Config
  686.  
  687. A single player game will only use the loopback code
  688. ====================
  689. */
  690. void    NET_Config (qboolean multiplayer)
  691. {
  692.     int        i;
  693.     static    qboolean    old_config;
  694.  
  695.     if (old_config == multiplayer)
  696.         return;
  697.  
  698.     old_config = multiplayer;
  699.  
  700.     if (!multiplayer)
  701.     {    // shut down any existing sockets
  702.         for (i=0 ; i<2 ; i++)
  703.         {
  704.             if (ip_sockets[i])
  705.             {
  706.                 closesocket (ip_sockets[i]);
  707.                 ip_sockets[i] = 0;
  708.             }
  709.             if (ipx_sockets[i])
  710.             {
  711.                 closesocket (ipx_sockets[i]);
  712.                 ipx_sockets[i] = 0;
  713.             }
  714.         }
  715.     }
  716.     else
  717.     {    // open sockets
  718.         if (! noudp->value)
  719.             NET_OpenIP ();
  720.         if (! noipx->value)
  721.             NET_OpenIPX ();
  722.     }
  723. }
  724.  
  725. // sleeps msec or until net socket is ready
  726. void NET_Sleep(int msec)
  727. {
  728.     struct timeval timeout;
  729.     fd_set    fdset;
  730.     extern cvar_t *dedicated;
  731.     int i;
  732.  
  733.     if (!dedicated || !dedicated->value)
  734.         return; // we're not a server, just run full speed
  735.  
  736.     FD_ZERO(&fdset);
  737.     i = 0;
  738.     if (ip_sockets[NS_SERVER]) {
  739.         FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
  740.         i = ip_sockets[NS_SERVER];
  741.     }
  742.     if (ipx_sockets[NS_SERVER]) {
  743.         FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
  744.         if (ipx_sockets[NS_SERVER] > i)
  745.             i = ipx_sockets[NS_SERVER];
  746.     }
  747.     timeout.tv_sec = msec/1000;
  748.     timeout.tv_usec = (msec%1000)*1000;
  749.     select(i+1, &fdset, NULL, NULL, &timeout);
  750. }
  751.  
  752. //===================================================================
  753.  
  754.  
  755. static WSADATA        winsockdata;
  756.  
  757. /*
  758. ====================
  759. NET_Init
  760. ====================
  761. */
  762. void NET_Init (void)
  763. {
  764.     WORD    wVersionRequested; 
  765.     int        r;
  766.  
  767.     wVersionRequested = MAKEWORD(1, 1); 
  768.  
  769.     r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
  770.  
  771.     if (r)
  772.         Com_Error (ERR_FATAL,"Winsock initialization failed.");
  773.  
  774.     Com_Printf("Winsock Initialized\n");
  775.  
  776.     noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
  777.     noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
  778.  
  779.     net_shownet = Cvar_Get ("net_shownet", "0", 0);
  780. }
  781.  
  782.  
  783. /*
  784. ====================
  785. NET_Shutdown
  786. ====================
  787. */
  788. void    NET_Shutdown (void)
  789. {
  790.     NET_Config (false);    // close sockets
  791.  
  792.     WSACleanup ();
  793. }
  794.  
  795.  
  796. /*
  797. ====================
  798. NET_ErrorString
  799. ====================
  800. */
  801. char *NET_ErrorString (void)
  802. {
  803.     int        code;
  804.  
  805.     code = WSAGetLastError ();
  806.     switch (code)
  807.     {
  808.     case WSAEINTR: return "WSAEINTR";
  809.     case WSAEBADF: return "WSAEBADF";
  810.     case WSAEACCES: return "WSAEACCES";
  811.     case WSAEDISCON: return "WSAEDISCON";
  812.     case WSAEFAULT: return "WSAEFAULT";
  813.     case WSAEINVAL: return "WSAEINVAL";
  814.     case WSAEMFILE: return "WSAEMFILE";
  815.     case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
  816.     case WSAEINPROGRESS: return "WSAEINPROGRESS";
  817.     case WSAEALREADY: return "WSAEALREADY";
  818.     case WSAENOTSOCK: return "WSAENOTSOCK";
  819.     case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
  820.     case WSAEMSGSIZE: return "WSAEMSGSIZE";
  821.     case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
  822.     case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
  823.     case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
  824.     case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
  825.     case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
  826.     case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
  827.     case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
  828.     case WSAEADDRINUSE: return "WSAEADDRINUSE";
  829.     case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
  830.     case WSAENETDOWN: return "WSAENETDOWN";
  831.     case WSAENETUNREACH: return "WSAENETUNREACH";
  832.     case WSAENETRESET: return "WSAENETRESET";
  833.     case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
  834.     case WSAECONNRESET: return "WSAECONNRESET";
  835.     case WSAENOBUFS: return "WSAENOBUFS";
  836.     case WSAEISCONN: return "WSAEISCONN";
  837.     case WSAENOTCONN: return "WSAENOTCONN";
  838.     case WSAESHUTDOWN: return "WSAESHUTDOWN";
  839.     case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
  840.     case WSAETIMEDOUT: return "WSAETIMEDOUT";
  841.     case WSAECONNREFUSED: return "WSAECONNREFUSED";
  842.     case WSAELOOP: return "WSAELOOP";
  843.     case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
  844.     case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
  845.     case WSASYSNOTREADY: return "WSASYSNOTREADY";
  846.     case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
  847.     case WSANOTINITIALISED: return "WSANOTINITIALISED";
  848.     case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
  849.     case WSATRY_AGAIN: return "WSATRY_AGAIN";
  850.     case WSANO_RECOVERY: return "WSANO_RECOVERY";
  851.     case WSANO_DATA: return "WSANO_DATA";
  852.     default: return "NO ERROR";
  853.     }
  854. }
  855.